const Cesium = require('cesium')

class CesiumAlgo {
  constructor(id, mode) {
    if (!id) return
    this.viewer = null;
    // 构造函数，初始化viwer对象
    (() => {
      // 墨卡托投影系加载
      const tms = new Cesium.UrlTemplateImageryProvider({
        url: '../../static/wxmaps/{z}/{x}/{y}.jpg',
        // url: 'http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali',
        tilingScheme: new Cesium.WebMercatorTilingScheme(), // 解析规则  墨卡托
        maximumLevel: 7 // 最大层级
      })
      // 加载wmts地图服务
      // var wmts = new Cesium.WebMapTileServiceImageryProvider({
      //   url: 'http://192.168.1.10:8198/geowebcache/service/wmts',
      //   layer: 'sate-map',
      //   tileMatrixSetID: 'EPSG:4326_sate-map',
      //   tileMatrixLabels: [
      //     'EPSG:4326_sate-map:1',
      //     'EPSG:4326_sate-map:2',
      //     'EPSG:4326_sate-map:3',
      //     'EPSG:4326_sate-map:4',
      //     'EPSG:4326_sate-map:5',
      //     'EPSG:4326_sate-map:6',
      //     'EPSG:4326_sate-map:7',
      //     'EPSG:4326_sate-map:8',
      //     'EPSG:4326_sate-map:9',
      //     'EPSG:4326_sate-map:10',
      //     'EPSG:4326_sate-map:11',
      //     'EPSG:4326_sate-map:12',
      //     'EPSG:4326_sate-map:13',
      //     'EPSG:4326_sate-map:14',
      //     'EPSG:4326_sate-map:15',
      //     'EPSG:4326_sate-map:16',
      //     'EPSG:4326_sate-map:17',
      //     'EPSG:4326_sate-map:18',
      //     'EPSG:4326_sate-map:19'
      //   ],
      //   format: 'image/jpeg',
      //   tilingScheme: new Cesium.GeographicTilingScheme({
      //     ellipsoid: Cesium.Ellipsoid.WGS84
      //   }), //解析规则
      //   minimumLevel: 1,
      //   maximumLevel: 11,
      // })
      // 初始化视角
      const china = Cesium.Rectangle.fromDegrees(100, -60, 110, 90)
      Cesium.Camera.DEFAULT_VIEW_RECTANGLE = china

      // 初始化地球
      this.viewer = new Cesium.Viewer(id, {
        imageryProvider: tms,
        // imageryProvider:new Cesium.ArcGisMapServerImageryProvider({
        //   url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
        // }),
        // terrainProvider: new Cesium.ArcGISTiledElevationTerrainProvider({
        //   url : 'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
        //   token : 'KED1aF_I4UzXOHy3BnhwyBHU4l5oY6rO6walkmHoYqGp4XyIWUd5YZUC1ZrLAzvV40pR6gBXQayh0eFA8m6vPg..'
        // }),
        terrainProvider: new Cesium.CesiumTerrainProvider({
          url : Cesium.IonResource.fromAssetId(3956),
          requestVertexNormals : true
        }),
        sceneMode: mode === '2D' ? Cesium.SceneMode.SCENE2D : Cesium.SceneMode.SCENE3D,
        shouldAnimate: true, // 自动播放
        // terrainProvider: terrain,//加载地形
        animation: true, // 是否显示动画控制器
        timeline: true, // 是否显示时间轴
        baseLayerPicker: false, // 是否显示地图底图切换控件  明确如何设置不同地图的访问路径  似乎离线必须要设置成false
        homeButton: false, // 是否显示主页控件  默认是true
        sceneModePicker: false,
        navigationHelpButton: false, // 是否显示帮助按钮
        geocoder: false, // 是否显示地名查找控件
        fullscreenButton: false, // 全屏按钮
        vrButton: false, // 是否启用地图双屏控件  感觉没用。。。。
        infoBox: false, // 是否显示默认气泡窗口控件  默认true
        selectionIndicator: true, // 是否显示选中元素标识控件 默认true  通常和上面的infoBox搭配使用
        shadows: false,
        // terrainShadows:RECEIVE_ONLY,
        skyBox: new Cesium.SkyBox({
          sources: {
            positiveX: '../../static/SkyBox/tycho2t3_80_px.jpg',
            negativeX: '../../static/SkyBox/tycho2t3_80_mx.jpg',
            positiveY: '../../static/SkyBox/tycho2t3_80_py.jpg',
            negativeY: '../../static/SkyBox/tycho2t3_80_my.jpg',
            positiveZ: '../../static/SkyBox/tycho2t3_80_pz.jpg',
            negativeZ: '../../static/SkyBox/tycho2t3_80_mz.jpg'
          }
        })
      })
      // 去掉版权
      this.viewer._cesiumWidget._creditContainer.style.display = 'none'
      // 控制视角不转到地下
      // this.viewer.scene.globe.depthTestAgainstTerrain = true;
      // 隐藏 animation 和 timeline
      // this.viewer.animation.container.style.visibility = 'hidden'
      // this.viewer.timeline.container.style.visibility = 'hidden'
      // 启用地球照明   打开昼夜分界线
      // this.viewer.scene.globe.enableLighting = true;
      // 启用雾
      // this.viewer.scene.fog.enabled = true;
      // this.viewer.scene.skyAtmosphere = true;
      // 开启模型检查器
      // this.viewer.extend(Cesium.this.viewerCesiumInspectorMixin);


      const date = new Date()
      // 可返回格林威治时间和本地时间之间的时差
      const h = 0 - date.getTimezoneOffset()
      this.viewer.animation.viewModel.timeFormatter = function (date, viewModel) {
        // 重新构造一个当前系统时间的儒略日
        const dateZone = Cesium.JulianDate.addMinutes(date, h, new Cesium.JulianDate())
        const gregorianDate = Cesium.JulianDate.toGregorianDate(dateZone)
        const millisecond = Math.round(gregorianDate.millisecond)
        // 倍速是否小于1，小于1则显示毫秒级
        if (Math.abs(viewModel._clockViewModel.multiplier) < 1) {
          return Cesium.sprintf('%02d:%02d:%02d.%03d', gregorianDate.hour, gregorianDate.minute, gregorianDate.second, gregorianDate.millisecond)
        }
        return Cesium.sprintf('%02d:%02d:%02d', gregorianDate.hour, gregorianDate.minute, gregorianDate.second)
      }
      // 设置日期
      this.viewer.animation.viewModel.dateFormatter = function (date, viewModel) {
        const dateZone = Cesium.JulianDate.addMinutes(date, h, new Cesium.JulianDate())
        const gregorianDate = Cesium.JulianDate.toGregorianDate(dateZone)
        // 设置格式为xx/xx/xx，格式可自定义为任意你想要的
        return Cesium.sprintf('%4d-%02d-%02d', gregorianDate.year, gregorianDate.month, gregorianDate.day)
      }
    })()
  }

  /**
   * 点
   * @param {} id       点编号
   * @param {} name     点名称
   * @param {} color    颜色
   * @param {} size     点大小
   * @param {} lon      经度
   * @param {} lat      纬度
   */
  renderPoint(id, name, color, size, lon, lat) {
    return this.viewer.entities.add({
      id,
      name,
      position: Cesium.Cartesian3.fromDegrees(lon, lat),
      point: {
        pixelSize: size,
        color: Cesium.Color.fromCssColorString(color)
      },
      label: {
        text: name,
        font: '12px sans-serif',
        pixelOffset: new Cesium.Cartesian2(0, -20), // y大小根据行数和字体大小改变
        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
        backgroundPadding: new Cesium.Cartesian2(5, 5),
        showBackground: true,
        backgroundColor: Cesium.Color.fromCssColorString('rgba(15, 44, 88, .8)')
      }
    })
  }

  /**
   * 线
   * @param {} id         线编号
   * @param {} name       线名称
   * @param {} color      颜色
   * @param {} width      点大小
   * @param {} position    位置 经度，纬度，经度，纬度
   */
  renderLine(id, name, color, width, position) {
    return this.viewer.entities.add({
      id,
      name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray(position),
        width,
        material: Cesium.Color.fromCssColorString(color)
      }
    })
  }

  /**
   * 虚线
   * @param {} id         线编号
   * @param {} name       线名称
   * @param {} color      颜色
   * @param {} width      点大小
   * @param {} position    位置 经度，纬度，高度，经度，纬度，高度
   */
  renderDashLine(id, name, color, width, position) {
    return this.viewer.entities.add({
      id,
      name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(position),
        width,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.fromCssColorString(color)
        })
      }
    })
  }

  /**
   * 圆形
   * @author Farley
   * @date 2020-10-20
   * @param {any} id
   * @param {any} name
   * @param {any} color
   * @param {any} diameter
   * @param {any} position
   * @returns {any}
   */
  renderCylinder(id, name, color, lineColor, diameter, position) {
    return this.viewer.entities.add({
      id,
      name,
      position: Cesium.Cartesian3.fromDegrees(...position),
      ellipse: {
        semiMinorAxis: diameter,
        semiMajorAxis: diameter,
        height: 0,
        material: new Cesium.Color.fromCssColorString(color),
        outline: true,
        outlineWidth: 5,
        outlineColor: Cesium.Color.fromCssColorString(lineColor)
      }
    })
  }

  /**
   * 多边形
   * @param {} id         多边形编号
   * @param {} name       多边形名称
   * @param {} color      颜色
   * @param {} position    位置 经度，纬度，经度，纬度
   */
  renderPolygon(id, name, color, position) {
    return this.viewer.entities.add({
      id,
      name,
      polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray(position),
        material: Cesium.Color.fromCssColorString(color)
      }
    })
  }

  /**
   * 流动纹理线
   * @param {} id         线编号
   * @param {} name       线名称
   * @param {} color      颜色
   * @param {} width      点大小
   * @param {} position    位置 经度，纬度，经度，纬度
   */
  renderFlowLine(canvas, id, name, width, position) {
    // 通过3个画布交替切换实现纹理动态
    let changenum = 3
    let curCanvas = 'a'
    canvas.map(item => {
      const canvas = document.getElementById(item[0])
      const cwidth = 400
      const cheight = 40
      const ctx = canvas.getContext('2d')
      ctx.clearRect(0, 0, cwidth, cheight)
      ctx.fillStyle = 'rgba(255, 255, 255, 0)'
      ctx.fillRect(0, 0, cwidth, cheight)

      for (let ii = 0; item[1] <= 400; ii++) {
        ctx.lineWidth = 5
        // 开始一个新的绘制路径
        ctx.beginPath()
        // 设置弧线的颜色
        ctx.strokeStyle = 'rgba(250, 74, 68, 1)'
        // 以canvas中左上角画一根长400px的直线
        ctx.moveTo(item[1], 0)
        ctx.lineTo(item[1] + 10, 20)
        ctx.lineTo(item[1], 40)
        // 按照指定的路径绘制
        ctx.stroke()
        item[1] += 15
      }
    })

    viewer.entities.add({
      id,
      name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(position),
        width,
        material: new Cesium.ImageMaterialProperty({
          image: new Cesium.CallbackProperty(() => {
            changenum++
            const canvas = document.getElementById('canvas-' + curCanvas)
            if (changenum >= 3) {
              changenum = 0
              if (curCanvas === '3') {
                curCanvas = '2'
              } else if (curCanvas === '2') {
                curCanvas = '1'
              } else {
                curCanvas = '3'
              }
            }
            return canvas
          }, false),
          transparent: true
        }),
        arcType: Cesium.ArcType.NONE
      }
    })
  }

  /**
   * 箭头曲线
   * @param {} id         线编号
   * @param {} name       线名称
   * @param {} color      颜色
   * @param {} width      点大小
   * @param {} position    位置 经度，纬度，经度，纬度
   */
  renderArrowLine(id, name, color, width, position) {
    this.viewer.entities.add({
      id,
      name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(position),
        width,
        material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString(color))
        // clampToGround: true
      }
    })
  }

  /**
   * 卫星轨道
   * @param {} id         轨道编号
   * @param {} name       轨道名称
   * @param {} color      颜色
   * @param {} width      点大小
   * @param {} positon    位置 经度，纬度，经度，纬度
   */
  renderSatOrbital(id, name, color, width, position) {
    this.viewer.entities.add({
      id,
      name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(position),
        width,
        // arcType: Cesium.ArcType.RHUMB,
        material: Cesium.Color.fromCssColorString(color)
      }
    })
  }

  /**
   * 添加模型
   * @param {} id         卫星id
   * @param {} name       卫星名称
   * @param {} lon        模型经度
   * @param {} lat        模型纬度
   * @param {} height     模型高度
   * @param {} uri        模型路径
   * @param {} heading    模型偏航角
   * @param {} pitch      模型俯仰角
   * @param {} roll       模型滚动角
   * @param {} minSize    模型最小尺寸
   */
  renderModel(id, name, lon, lat, height, uri, heading = 0, pitch = 90, roll = 0, minSize = 150) {
    const position = Cesium.Cartesian3.fromDegrees(lon, lat, height) // 设置位置
    const headingNum = Cesium.Math.toRadians(heading) // 设置偏航角
    const pitchNum = Cesium.Math.toRadians(pitch) // 设置俯仰角
    const rollNum = roll // 设置滚动角
    const hpr = new Cesium.HeadingPitchRoll(headingNum, pitchNum, rollNum) // 生成四元数
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr) // 设置姿态
    this.viewer.entities.add({
      id,
      name,
      position: position,
      orientation,
      model: {
        uri,
        minimumPixelSize: minSize
        // maximumScale: 20000
      }
    })
  }

  /**
   * 添加卫星模型（模型节点控制动画）
   * @param {} id         卫星id
   * @param {} name       卫星名称
   * @param {} lon        模型经度
   * @param {} lat        模型纬度
   * @param {} height     模型高度
   * @param {} url        模型路径
   * @param {} node       模型节点名称
   * @param {} heading    模型偏航角
   * @param {} pitch      模型俯仰角
   * @param {} roll       模型滚动角
   * @param {} minSize    模型最小尺寸
   */
  renderSatModel(id, lon, lat, height, url, node, minSize = 150) {
    const quat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Y, Cesium.Math.toRadians(90)) // Cesium.Cartesian3.UNIT_Z初始化（0.0,1.0,0.0）
    const mat3 = Cesium.Matrix3.fromQuaternion(quat)
    const mat4 = Cesium.Matrix4.fromRotationTranslation(mat3, Cesium.Cartesian3.ZERO) // Cesium.Cartesian3.ZERO 初始化（0.0,0.0,0.0）
    const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(lon, lat, height))
    const m = Cesium.Matrix4.multiplyTransformation(modelMatrix, mat4, new Cesium.Matrix4())
    const modelss = this.viewer.scene.primitives.add(Cesium.Model.fromGltf({
      id,
      url,
      modelMatrix: m,
      scale: 1,
      minimumPixelSize: minSize
    }))
    // 卫星太阳板动画
    const nodeName = node
    Cesium.when(modelss.readyPromise).then(function (modelss) {
      // 初始角度
      let i = 60
      let flag = false
      setInterval(() => {
        if (i === 60) {
          flag = true
        } else if (i === -60) {
          flag = false
        }
        if (flag) {
          i -= 2
        } else {
          i += 2
        }
        nodeName.map(item => {
          const node = modelss.getNode(item)
          const quat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Y, Cesium.Math.toRadians(i)) // Cesium.Cartesian3.UNIT_Z初始化（0.0,1.0,0.0）
          const pt = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, Cesium.Math.toRadians(90)) // Cesium.Cartesian3.UNIT_Z初始化（0.0,1.0,0.0）
          const mat3 = Cesium.Matrix3.fromQuaternion(quat)
          node.matrix = Cesium.Matrix4.fromRotationTranslation(mat3, pt, node.matrix)
        })
      }, 50)
    })
  }

  /**
   * 视角锁定
   * @param {} id  模型 id
   */
  flyToTarget(id) {
    const targetEntity = this.viewer.entities.getById(id)
    const position = targetEntity.position
    const ellipsoid = this.viewer.scene.globe.ellipsoid
    const cartesian3 = new Cesium.Cartesian3(position._value.x, position._value.y, position._value.z)
    const cartographic = ellipsoid.cartesianToCartographic(cartesian3)
    const lon = Cesium.Math.toDegrees(cartographic.longitude)
    const lat = Cesium.Math.toDegrees(cartographic.latitude)
    const alt = cartographic.height
    // 选择当前 entity
    this.viewer.selectedEntity = targetEntity
    this.viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(lon, lat + 1, alt + 10000000),
      orientation: {
        heading: Cesium.Math.toRadians(0),
        pitch: Cesium.Math.toRadians(-90),
        roll: 0
      },
      // 动画持续时间
      duration: 1.5
    })
    // 初始化视角跟踪
    this.viewer.trackedEntity = this.viewer
    // 设置视角跟踪
    this.viewer.trackedEntity = targetEntity
  }

  /**
   * 创建卫星波束
   * @author Farley
   * @date 2021-01-21
   * @param {any} id
   * @param {any} stltPos
   * @param {any} points
   * @param {any} shellcolor
   * @param {any} type
   * @param {any} workState
   * @returns {any}
   */
  renderSatBeam(id, stltPos, points, shellcolor, type, workState) {
    let numtriangles = points.length / 3;
    let arr = [stltPos[0], stltPos[1], stltPos[2]];
    let arrZero = [];
    for (let i = 0; i < points.length; i += 3) {
      if (i + 3 === points.length) {
        arr.push(points[0], points[1], points[2]);
      } else {
        if (points[i + 2] < 10) {
          arrZero.push(points[i], points[i + 1], points[i + 2]);
        }
        arr.push(points[i], points[i + 1], points[i + 2])
      }
    }
    let myPositions = Cesium.Cartesian3.fromDegreesArrayHeights(arr);
    let positions = new Float64Array(3 * (numtriangles * 2 + 1));
    let sts = new Float32Array(2 * (numtriangles * 2 + 1));
    let indices = new Uint16Array(3 * numtriangles);

    positions[0] = myPositions[0].x;
    positions[1] = myPositions[0].y;
    positions[2] = myPositions[0].z;
    sts[0] = 0.5;
    sts[1] = 1.0;
    let vertexcount = 2;
    let stcount = 1;
    let indexcount = 0;
    let distance = Cesium.Cartesian3.distance(myPositions[1], myPositions[0]);
    let tempdistance = Cesium.Cartesian3.distance(myPositions[1], myPositions[0]);
    for (var i = 0; i < myPositions.length - 2; i++) {
      positions[++vertexcount] = myPositions[i + 1].x;
      positions[++vertexcount] = myPositions[i + 1].y;
      positions[++vertexcount] = myPositions[i + 1].z;
      sts[++stcount] = 0.0;
      tempdistance = Cesium.Cartesian3.distance(myPositions[i + 1], myPositions[0]);
      sts[++stcount] = 1.0 - tempdistance / distance;
      if (sts[stcount] < 0) sts[stcount] = 0;

      positions[++vertexcount] = myPositions[i + 2].x;
      positions[++vertexcount] = myPositions[i + 2].y;
      positions[++vertexcount] = myPositions[i + 2].z;
      sts[++stcount] = 1.0;
      tempdistance = Cesium.Cartesian3.distance(myPositions[i + 2], myPositions[0]);
      sts[++stcount] = 1.0 - tempdistance / distance;
      if (sts[stcount] < 0) sts[stcount] = 0;

      indices[indexcount++] = 0;
      indices[indexcount++] = i * 2 + 1;
      indices[indexcount++] = i * 2 + 2;
    }
    let geometry = new Cesium.Geometry({
      attributes: {
        position: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.DOUBLE,
          componentsPerAttribute: 3,
          values: positions
        }),
        st: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.FLOAT,
          componentsPerAttribute: 2,
          values: sts
        }),
      },
      indices: indices,
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
    });
    /**
     * 判断接收数据的workState
     * 0 静态
     * 1 动态
     */
    if (workState === 0) {
      workState = false
    } else if (workState === 1) {
      workState = true
    } else {
      workState = false
    }
    /**
     * 判断接收数据的type
     * 1 是吞圈 侦查
     * 其余的是吐圈 类型2
     * 3 类型3
     * 4 遥测
     * 5 遥控
     * 6 类型5
     */
    let color;
    if (type === 1) {
      type = true;
      color = "rgb(16,255,209)"
    } else if (type === 2) {
      type = false;
      color = "rgb(255,0,0)"
    } else if (type === 3) {
      type = false;
      color = "rgb(6,118,255)"
    } else if (type === 4) {
      type = false;
      color = "rgb(21,75,255)"
    } else if (type === 5) {
      type = false;
      color = "rgb(0,255,192)"
    } else if (type === 6) {
      type = false;
      color = "rgb(10,245,255)"
    } else {
      type = false;
      color = "rgb(35,248,255)"
    }
    let instance = new Cesium.GeometryInstance({
      geometry: geometry,
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(shellcolor))
      },
    });
    let staticAppearance = new Cesium.PerInstanceColorAppearance({
      translucent: true,
    });
    let dynamicAppearance = new Cesium.MaterialAppearance({
      material: new Cesium.Material({
        fabric: {
          type: "radarS",
          uniforms: {
            color: Cesium.Color.fromCssColorString(color),
            shellcolor: Cesium.Color.fromCssColorString(shellcolor),
            repeat: 10, // 重复度
            offset: 0,
            speed: (type ? -1 : 1) * 5,
            thickness: 0.4 // 每个条纹之间的间隔
          },
          source: "\n uniform vec4 color;\n" +
            "uniform vec4 shellcolor;\n" +
            "uniform float repeat;\n" +
            "uniform float offset;\n" +
            "uniform float thickness;\n" +
            "uniform float speed;\n" +
            "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
            "{\n" +
            "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
            "float sp = 1.0/repeat;\n" +
            "vec2 st = materialInput.st;\n" +
            "float dis = 1.0-st.t;\n" +
            "float m = mod(dis + offset-czm_frameNumber*0.001*speed, sp);\n" +
            "float a = step(sp*(1.0-thickness), m);\n" +
            "material.diffuse = shellcolor.rgb+shellcolor.rgb;\n" +
            // "material.diffuse = a*color.rgb+(1.0-a)*shellcolor.rgb;\n" +
            "material.alpha = a * color.a+shellcolor.a;\n" +
            "return material;\n" +
            "}\n"
        },
        translucent: false
      }),
      closed: true
    });
    let primitive = new Cesium.Primitive({
      geometryInstances: [instance],
      appearance: workState ? dynamicAppearance : staticAppearance,
      asynchronous: false
    });
    // 创建切面
    if (arrZero.length !== 0) {
      arrZero.push(arrZero[0], arrZero[1], arrZero[2]);
      if (workState) {
        if (this.viewer.entities.getById(id + "zero")) {
          this.updateBeamLine(id + "zero", arrZero, shellcolor, 0.5);
        } else {
          this.createBeamLine(id + "zero", arrZero, shellcolor, 0.5);
        }
      } else {
        if (this.viewer.entities.getById(id + "zero")) {
          this.updateBeamLine(id + "zero", arrZero, shellcolor, 0.5);
        } else {
          this.createBeamLine(id + "zero", arrZero, shellcolor, 0.5);
        }
      }
    }
    this.viewer.scene.primitives.add(primitive);
    return primitive
  }

  /**
   * 创建波束底部线
   * @author Farley
   * @date 2021-01-21
   * @param {any} id
   * @param {any} polylineArr
   * @param {any} color
   * @param {any} alpha
   * @returns {any}
   */
  createBeamLine(id, polylineArr, color, alpha) {
    let line = this.viewer.entities.add({
      id: id,
      show: true,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(polylineArr),
        width: 2,
        material: Cesium.Color.fromAlpha(Cesium.Color.fromCssColorString(color), alpha)
      }
    });
    return line;
  }

  /**
   * 更新波束底部线
   * @author Farley
   * @date 2021-01-21
   * @param {any} id
   * @param {any} polylineArr
   * @param {any} color
   * @param {any} alpha
   * @returns {any}
   */
  updateBeamLine(id, polylineArr, color, alpha) {
    this.viewer.entities.getById(id).polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights(polylineArr);
    this.viewer.entities.getById(id).polyline.meterial = Cesium.Color.fromAlpha(Cesium.Color.fromCssColorString(color), alpha);
  };

  /**
   * 卫星轨道动画
   * @param {} data       [[秒, 经度, 纬度, 高度], [秒, 经度, 纬度, 高度]]
   * @param {} id         模型编号
   * @param {} sTime      开始时间
   * @param {} timeRate   播放速度
   */
  sateAnimation(data, id, sTime, timeRate) {
    // 持续时间
    const eTime = data[data.length - 1][0]
    // 开始时间
    const start = Cesium.JulianDate.fromDate(new Date(sTime))
    // 结束时间
    const stop = Cesium.JulianDate.addSeconds(start, eTime, new Cesium.JulianDate())
    // 设置开始时间轴
    this.viewer.clock.startTime = start
    // 设置当前时间轴
    this.viewer.clock.currentTime = start
    // 设置结束时间轴
    this.viewer.clock.stopTime = stop
    // 时间速率
    this.viewer.clock.multiplier = timeRate
    // 时间轴
    this.viewer.timeline.zoomTo(start, stop)
    // 循环执行 到达终点时间 重新从起点时间开始
    this.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP
    const property = new Cesium.SampledPositionProperty()
    for (let i = 0; i < data.length; i++) {
      const time = Cesium.JulianDate.addSeconds(start, data[i][0], new Cesium.JulianDate())
      const position = Cesium.Cartesian3.fromDegrees(data[i][1], data[i][2], data[i][3])
      // 添加位置，和时间对应
      property.addSample(time, position)
    }
    const model = this.viewer.entities.getById(id)
    // 关联时间轴
    model.availability = new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
      start,
      stop
    })])
    model.position = property
    model.orientation = new Cesium.VelocityOrientationProperty(property)
  }

  /**
   * 创建时间控件
   * @param {} startTime      开始时间
   * @param {} endTime        结束时间
   */
  renderTimeControls(startTime, stopTime) {
    let clock
    const animationContainer = document.getElementsByClassName('animation')[0]
    const timelineContainer = document.getElementsByClassName('time-line')[0]
    clock = new Cesium.Clock({
      startTime: Cesium.JulianDate.fromIso8601(startTime),
      currentTime: Cesium.JulianDate.fromIso8601(stopTime),
      stopTime: Cesium.JulianDate.fromIso8601(stopTime),
      clockRange: Cesium.ClockRange.LOOP_STOP,
      clockStep: Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER
    })
    // 时间轴默认开始
    clock.shouldAnimate = true
    // 创建ViewModel
    const clockViewModel = new Cesium.ClockViewModel(clock)
    const animation = new Cesium.Animation(animationContainer, new Cesium.AnimationViewModel(clockViewModel))
    const timeline = new Cesium.Timeline(timelineContainer, clock)
  }

  /**
   * 加载 3D Tiles 数据
   * @param {} url    路径
   */
  render3DTiles(url) {
    // 加载数据
    const city = this.viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
      url
    }))
    // 调整 3dTiles 样式
    // 根据高度的不同，指定不同的颜色、
    const heightStyle = new Cesium.Cesium3DTileStyle({
      color: {
        conditions: [
          ['${height} >= 300', 'rgba(45, 0, 75, 0.5)'],
          ['${height} >= 200', 'rgb(102, 71, 151)'],
          ['${height} >= 100', 'rgb(170, 162, 204)'],
          ['${height} >= 50', 'rgb(224, 226, 238)'],
          ['${height} >= 25', 'rgb(252, 230, 200)'],
          ['${height} >= 10', 'rgb(248, 176, 87)'],
          ['${height} >= 5', 'rgb(198, 106, 11)'],
          ['true', 'rgb(127, 59, 8)']
        ]
      }
    })

    // 指定 city 样式
    city.style = heightStyle
  }

  /**
   * 加载 geojson 数据
   * @param {} url    路径
   */
  renderGeoJson(url) {
    const geojsonOptions = {
      // 贴地
      clampToGround: true
    }
    const neighborhoodsPromise = Cesium.GeoJsonDataSource.load(url,
      geojsonOptions)

    neighborhoodsPromise.then(function (dataSource) {
      // 把数据加载大搜场景里
      this.viewer.dataSources.add(dataSource)
      // 遍历数据
      const neighborhoodEntities = dataSource.entities.values
      for (let i = 0; i < neighborhoodEntities.length; i++) {
        const entity = neighborhoodEntities[i]

        if (Cesium.defined(entity.polygon)) {
          // 每个区块的名字
          entity.name = entity.properties.neighborhood
          // 每个多边形的材质  随机颜色
          entity.polygon.material = Cesium.Color.fromRandom({
            red: 0.1,
            maximumGreen: 0.5,
            minimumBlue: 0.5,
            alpha: 0.3
          })
          // 地理区块贴在地面之上
          entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN
          // 从多边形里取出顶点
          const polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions
          // 通过顶点构建包围球 取出中心点
          let polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center
          // 包围球中心点做贴地偏移
          polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter)
          // 赋值
          entity.position = polyCenter
          // 创建标签，标签在中心点显示
          entity.label = {
            text: entity.name,
            showBackground: true,
            scale: 0.6,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 8000.0),
            disableDepthTestDistance: 100.0
          }
        }
      }
    })
  }

  /**
   * 圆形扩散扫描
   * @param {} lon          经度
   * @param {} lat          纬度
   * @param {} r            最大半径
   * @param {} color        颜色
   * @param {} duration     持续时间
   */
  renderCircleScan(lon, lat, r, color, duration) {
    // 防止移动、放大缩小会视觉偏移depthTestAgainstTerrain
    // 设置该属性为true之后，标绘将位于地形的顶部；如果设为false（默认值），那么标绘将位于平面上。
    // 缺陷：开启该属性有可能在切换图层时会引发标绘消失的bug。
    this.viewer.scene.globe.depthTestAgainstTerrain = true
    // 中心位子
    const cartographicCenter = new Cesium.Cartographic(Cesium.Math.toRadians(lon), Cesium.Math.toRadians(lat), 0)
    // 扫描颜色
    const scanColor = new Cesium.Color.fromCssColorString(color)

    const ScanSegmentShader =
      'uniform sampler2D colorTexture;\n' +
      'uniform sampler2D depthTexture;\n' +
      'varying vec2 v_textureCoordinates;\n' +
      'uniform vec4 u_scanCenterEC;\n' +
      'uniform vec3 u_scanPlaneNormalEC;\n' +
      'uniform float u_radius;\n' +
      'uniform vec4 u_scanColor;\n' +
      'vec4 toEye(in vec2 uv, in float depth)\n' +
      ' {\n' +
      ' vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));\n' +
      ' vec4 posInCamera =czm_inverseProjection * vec4(xy, depth, 1.0);\n' +
      ' posInCamera =posInCamera / posInCamera.w;\n' +
      ' return posInCamera;\n' +
      ' }\n' +
      'vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point)\n' +
      '{\n' +
      'vec3 v01 = point -planeOrigin;\n' +
      'float d = dot(planeNormal, v01) ;\n' +
      'return (point - planeNormal * d);\n' +
      '}\n' +
      'float getDepth(in vec4 depth)\n' +
      '{\n' +
      'float z_window = czm_unpackDepth(depth);\n' +
      'z_window = czm_reverseLogDepth(z_window);\n' +
      'float n_range = czm_depthRange.near;\n' +
      'float f_range = czm_depthRange.far;\n' +
      'return (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n' +
      '}\n' +
      'void main()\n' +
      '{\n' +
      'gl_FragColor = texture2D(colorTexture, v_textureCoordinates);\n' +
      'float depth = getDepth( texture2D(depthTexture, v_textureCoordinates));\n' +
      'vec4 viewPos = toEye(v_textureCoordinates, depth);\n' +
      'vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz, u_scanCenterEC.xyz, viewPos.xyz);\n' +
      'float dis = length(prjOnPlane.xyz - u_scanCenterEC.xyz);\n' +
      'if(dis < u_radius)\n' +
      '{\n' +
      'float f = 1.0 -abs(u_radius - dis) / u_radius;\n' +
      'f = pow(f, 4.0);\n' +
      'gl_FragColor = mix(gl_FragColor, u_scanColor, f);\n' +
      '}\n' +
      '}\n'

    const _Cartesian3Center = Cesium.Cartographic.toCartesian(cartographicCenter)
    const _Cartesian4Center = new Cesium.Cartesian4(_Cartesian3Center.x, _Cartesian3Center.y, _Cartesian3Center.z, 1)
    const _CartographicCenter1 = new Cesium.Cartographic(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height + 500)
    const _Cartesian3Center1 = Cesium.Cartographic.toCartesian(_CartographicCenter1)
    const _Cartesian4Center1 = new Cesium.Cartesian4(_Cartesian3Center1.x, _Cartesian3Center1.y, _Cartesian3Center1.z, 1)
    const _time = (new Date()).getTime()
    const _scratchCartesian4Center = new Cesium.Cartesian4()
    const _scratchCartesian4Center1 = new Cesium.Cartesian4()
    const _scratchCartesian3Normal = new Cesium.Cartesian3()
    const ScanPostStage = new Cesium.PostProcessStage({
      fragmentShader: ScanSegmentShader,
      uniforms: {
        u_scanCenterEC: function () {
          return Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center)
        },
        u_scanPlaneNormalEC: function () {
          const temp = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center)
          const temp1 = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1)
          _scratchCartesian3Normal.x = temp1.x - temp.x
          _scratchCartesian3Normal.y = temp1.y - temp.y
          _scratchCartesian3Normal.z = temp1.z - temp.z
          Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal)
          return _scratchCartesian3Normal
        },
        u_radius: function () {
          return r * (((new Date()).getTime() - _time) % duration) / duration
        },
        u_scanColor: scanColor
      }
    })
    this.viewer.scene.postProcessStages.add(ScanPostStage)
    return (ScanPostStage)
  }

  /**
   * 添加雷达扫描
   * @param {} lon          经度
   * @param {} lat          纬度
   * @param {} r            最大半径
   * @param {} color        颜色
   * @param {} duration     持续时间
   */
  renderRadarScan(lon, lat, r, color, duration) {
    // 防止移动、放大缩小会视觉偏移depthTestAgainstTerrain
    // 设置该属性为true之后，标绘将位于地形的顶部；如果设为false（默认值），那么标绘将位于平面上。
    // 缺陷：开启该属性有可能在切换图层时会引发标绘消失的bug。
    this.viewer.scene.globe.depthTestAgainstTerrain = true
    // 中心位子
    const cartographicCenter = new Cesium.Cartographic(Cesium.Math.toRadians(lon), Cesium.Math.toRadians(lat), 0)
    // 扫描颜色
    const scanColor = new Cesium.Color.fromCssColorString(color)

    const ScanSegmentShader =
      'uniform sampler2D colorTexture;\n' +
      'uniform sampler2D depthTexture;\n' +
      'varying vec2 v_textureCoordinates;\n' +
      'uniform vec4 u_scanCenterEC;\n' +
      'uniform vec3 u_scanPlaneNormalEC;\n' +
      'uniform vec3 u_scanLineNormalEC;\n' +
      'uniform float u_radius;\n' +
      'uniform vec4 u_scanColor;\n' +
      'vec4 toEye(in vec2 uv, in float depth)\n' +
      ' {\n' +
      ' vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));\n' +
      ' vec4 posInCamera =czm_inverseProjection * vec4(xy, depth, 1.0);\n' +
      ' posInCamera =posInCamera / posInCamera.w;\n' +
      ' return posInCamera;\n' +
      ' }\n' +
      'bool isPointOnLineRight(in vec3 ptOnLine, in vec3 lineNormal, in vec3 testPt)\n' +
      '{\n' +
      'vec3 v01 = testPt - ptOnLine;\n' +
      'normalize(v01);\n' +
      'vec3 temp = cross(v01, lineNormal);\n' +
      'float d = dot(temp, u_scanPlaneNormalEC);\n' +
      'return d > 0.5;\n' +
      '}\n' +
      'vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point)\n' +
      '{\n' +
      'vec3 v01 = point -planeOrigin;\n' +
      'float d = dot(planeNormal, v01) ;\n' +
      'return (point - planeNormal * d);\n' +
      '}\n' +
      'float distancePointToLine(in vec3 ptOnLine, in vec3 lineNormal, in vec3 testPt)\n' +
      '{\n' +
      'vec3 tempPt = pointProjectOnPlane(lineNormal, ptOnLine, testPt);\n' +
      'return length(tempPt - ptOnLine);\n' +
      '}\n' +
      'float getDepth(in vec4 depth)\n' +
      '{\n' +
      'float z_window = czm_unpackDepth(depth);\n' +
      'z_window = czm_reverseLogDepth(z_window);\n' +
      'float n_range = czm_depthRange.near;\n' +
      'float f_range = czm_depthRange.far;\n' +
      'return (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n' +
      '}\n' +
      'void main()\n' +
      '{\n' +
      'gl_FragColor = texture2D(colorTexture, v_textureCoordinates);\n' +
      'float depth = getDepth( texture2D(depthTexture, v_textureCoordinates));\n' +
      'vec4 viewPos = toEye(v_textureCoordinates, depth);\n' +
      'vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz, u_scanCenterEC.xyz, viewPos.xyz);\n' +
      'float dis = length(prjOnPlane.xyz - u_scanCenterEC.xyz);\n' +
      'float twou_radius = u_radius * 2.0;\n' +
      'if(dis < u_radius)\n' +
      '{\n' +
      'float f0 = 1.0 -abs(u_radius - dis) / u_radius;\n' +
      'f0 = pow(f0, 64.0);\n' +
      'vec3 lineEndPt = vec3(u_scanCenterEC.xyz) + u_scanLineNormalEC * u_radius;\n' +
      'float f = 0.0;\n' +
      'if(isPointOnLineRight(u_scanCenterEC.xyz, u_scanLineNormalEC.xyz, prjOnPlane.xyz))\n' +
      '{\n' +
      'float dis1= length(prjOnPlane.xyz - lineEndPt);\n' +
      'f = abs(twou_radius -dis1) / twou_radius;\n' +
      'f = pow(f, 3.0);\n' +
      '}\n' +
      'gl_FragColor = mix(gl_FragColor, u_scanColor, f + f0);\n' +
      '}\n' +
      '}\n'

    const _Cartesian3Center = Cesium.Cartographic.toCartesian(cartographicCenter)
    const _Cartesian4Center = new Cesium.Cartesian4(_Cartesian3Center.x, _Cartesian3Center.y, _Cartesian3Center.z, 1)
    const _CartographicCenter1 = new Cesium.Cartographic(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height + 500)
    const _Cartesian3Center1 = Cesium.Cartographic.toCartesian(_CartographicCenter1)
    const _Cartesian4Center1 = new Cesium.Cartesian4(_Cartesian3Center1.x, _Cartesian3Center1.y, _Cartesian3Center1.z, 1)
    const _CartographicCenter2 = new Cesium.Cartographic(cartographicCenter.longitude + Cesium.Math.toRadians(0.001), cartographicCenter.latitude, cartographicCenter.height)
    const _Cartesian3Center2 = Cesium.Cartographic.toCartesian(_CartographicCenter2)
    const _Cartesian4Center2 = new Cesium.Cartesian4(_Cartesian3Center2.x, _Cartesian3Center2.y, _Cartesian3Center2.z, 1)
    const _RotateQ = new Cesium.Quaternion()
    const _RotateM = new Cesium.Matrix3()
    const _time = (new Date()).getTime()
    const _scratchCartesian4Center = new Cesium.Cartesian4()
    const _scratchCartesian4Center1 = new Cesium.Cartesian4()
    const _scratchCartesian4Center2 = new Cesium.Cartesian4()
    const _scratchCartesian3Normal = new Cesium.Cartesian3()
    const _scratchCartesian3Normal1 = new Cesium.Cartesian3()
    const ScanPostStage = new Cesium.PostProcessStage({
      fragmentShader: ScanSegmentShader,
      uniforms: {
        u_scanCenterEC: function () {
          return Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center)
        },
        u_scanPlaneNormalEC: function () {
          const temp = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center)
          const temp1 = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1)
          _scratchCartesian3Normal.x = temp1.x - temp.x
          _scratchCartesian3Normal.y = temp1.y - temp.y
          _scratchCartesian3Normal.z = temp1.z - temp.z
          Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal)
          return _scratchCartesian3Normal
        },
        u_radius: r,
        u_scanLineNormalEC: function () {
          const temp = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center)
          const temp1 = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1)
          const temp2 = Cesium.Matrix4.multiplyByVector(this.viewer.camera._viewMatrix, _Cartesian4Center2, _scratchCartesian4Center2)
          _scratchCartesian3Normal.x = temp1.x - temp.x
          _scratchCartesian3Normal.y = temp1.y - temp.y
          _scratchCartesian3Normal.z = temp1.z - temp.z
          Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal)
          _scratchCartesian3Normal1.x = temp2.x - temp.x
          _scratchCartesian3Normal1.y = temp2.y - temp.y
          _scratchCartesian3Normal1.z = temp2.z - temp.z
          const tempTime = (((new Date()).getTime() - _time) % duration) / duration
          Cesium.Quaternion.fromAxisAngle(_scratchCartesian3Normal, tempTime * Cesium.Math.PI * 2, _RotateQ)
          Cesium.Matrix3.fromQuaternion(_RotateQ, _RotateM)
          Cesium.Matrix3.multiplyByVector(_RotateM, _scratchCartesian3Normal1, _scratchCartesian3Normal1)
          Cesium.Cartesian3.normalize(_scratchCartesian3Normal1, _scratchCartesian3Normal1)
          return _scratchCartesian3Normal1
        },
        u_scanColor: scanColor
      }
    })
    this.viewer.scene.postProcessStages.add(ScanPostStage)
    return (ScanPostStage)
  }

  /**
   * 卫星动画跟踪
   */
  flyToSat(id) {
    const targetEntity = this.viewer.entities.getById(id)
    // this.viewer.camera.flyTo({
    //   orientation: {
    //     heading: 0.48098280328767906,
    //     pitch: -0.40641901480345144,
    //     roll: 0,
    //   },
    //   // 动画持续时间
    //   duration: 1.5
    // });
    // 初始化视角跟踪
    this.viewer.trackedEntity = this.viewer
    // 设置视角跟踪
    this.viewer.trackedEntity = targetEntity
  }

  /**
   * 动态渲染多边形
   * @author Farley
   * @date 2020-10-19
   * @returns {Array}   点击获取的坐标数组
   */
  dynamicRenderPolygon() {
    this.leftClickHandler = null
    const positions = []
    let polyline, polygon
    this.leftClickHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
    this.leftClickHandler.setInputAction(e => {
      const ellipsoid = this.viewer.scene.globe.ellipsoid
      const position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid)
      const wgs84 = ellipsoid.cartesianToCartographic(position)
      const lon = Cesium.Math.toDegrees(wgs84.longitude)
      const lat = Cesium.Math.toDegrees(wgs84.latitude)
      positions.push(lon, lat)
      if (positions.length > 5) {
        if (polygon) {
          polygon.polygon.hierarchy = Cesium.Cartesian3.fromDegreesArray(positions)
        } else {
          /* id, name, color, position */
          polygon = this.renderPolygon('polygon', '', 'rgba(3, 255, 0, .3)', positions)
        }
      }
      if (positions.length > 3) {
        if (polyline) {
          polyline.polyline.positions = Cesium.Cartesian3.fromDegreesArray([...positions, positions[0], positions[1]])
        } else {
          /* id, name, color, width, position */
          polyline = this.renderDashLine('polyline', '', '#03ff00', 2, [...positions, positions[0], positions[1]])
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    return positions
  }

  /**
   * 移除左键单击事件
   * @author Farley
   * @date 2020-10-19
   * @returns {any}
   */
  removeLeftClickEvent() {
    // this.viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this.leftClickHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  /**
   * 渲染广告牌 billboard
   * @author Farley
   * @date 2020-10-20
   * @param {any} id          编号
   * @param {any} name        名称
   * @param {any} position    位置
   * @param {any} img         图片资源
   * @param {any} imgWidth    图片宽度
   * @param {any} imgHeight   图片高度
   * @param {any} isScale     是否随相机进行高度缩放
   * @returns {any}
   */
  renderBillboard(id, name, position, img, imgWidth = 30, imgHeight = 30, isScale = false, labelText = null, color = '#00ffff') {
    return this.viewer.entities.add({
      id,
      name,
      show: true,
      position: Cesium.Cartesian3.fromDegrees(...position),
      billboard: {
        image: img,
        width: imgWidth,
        height: imgHeight,
        // sizeInMeters: isScale,
        scaleByDistance: new Cesium.NearFarScalar(150, 3.0, 15000000, 1)
      },
      label: {
        text: labelText || null,
        show: labelText || false,
        font: '10pt Source Han Sans CN',
        pixelOffset: new Cesium.Cartesian2(5, 20),
        fillColor: Cesium.Color.fromAlpha(Cesium.Color.fromCssColorString(color), 1)
      }
    })
  }
}

export default CesiumAlgo
